﻿using System;
using System.Globalization;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.UI.Properties;
using ZedGraph;
using SoftwareConsulting.BI11.Studio.InternalServices;

namespace SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.ClassificationProblems
{
    /// <summary>
    /// Класс диалога матрицы классификации
    /// </summary>
    public partial class ClassificationMatrixDialog : RestorableForm
    {
        private IClassificationProblem _problem;//задача классификации
        private ClassificationQualityInfo _qualityInfo; //информация о качестве классификации        
        private ProjectExplorerForm _projectExplorer; //связь с Обозревателем Проекта
        private BarItem _bar;//бар        

        /// <summary>
        /// Инициализирует диалог
        /// </summary>
        private void Initialize()
        {            
            ErrorLevelBox.Text = (_qualityInfo.Error() * 100).ToString("0.00", CultureInfo.CurrentUICulture);
            CorrectModelBox.Text = _qualityInfo.IsCorrectModel(_projectExplorer.CurrentSettings.DiscriminantAnalysisMaxError) ?
                Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_CORRECTMODEL :
                Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_INCORRECTMODEL;            
            RangeClasses();
            BuildMatrix();
            bool withHelp = _projectExplorer.SimpleMode;
            ErrorLevelTipBox.Closed = !withHelp;            
        }

        /// <summary>
        /// Строит матрицу классификации
        /// </summary>
        private void BuildMatrix()
        {
            var matrix = _qualityInfo.GetClassificationMatrix();
            var classes = _problem.ClassesNames;
            int classesCount = classes.GetIndicatorValuesCount() - 1;//минус 1, т.к. 0й - [не важно]
            string[] classesNames = new string[classesCount + 1]; //+1, т.к. ИТОГО
            for (int i = 1; i <= classesCount; i++)//с первого, т.к. 0й - [не важно]
            {
                classesNames[i - 1] = classes.GetIndicatorValueByPosition(i).Value as string;
            }
            classesNames[classesCount] = Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_SUM;
            ClassificationMatrixSummary.SetColumns(classesNames);
            ClassificationMatrixSummary.SetRows(classesNames);
            matrix = ClassificationMatrixFactVerticalRadio.Checked ? matrix : matrix.GetTransposedMatrix();
            double[,] components = matrix.CloneComponents();
            for (int i = 0; i <= components.GetUpperBound(0); i++)
            {
                for (int j = 0; j <= components.GetUpperBound(1); j++)
                {
                    ClassificationMatrixSummary.SetValue(i, j, components[i, j].ToString("#0.00", CultureInfo.CurrentUICulture));
                }
            }
        }

        /// <summary>
        /// Ранжирует классы
        /// </summary>
        private void RangeClasses()
        {
            var classes = _problem.ClassesNames;
            string[] rangedClasses = _qualityInfo.ClassesRangedByError(RangedClassesDescendingRadio.Checked);//descending потому что в UI сортировка по точности, а не по ошибке
            int[] failsClasses = _qualityInfo.ClassesFailsRangedByError(RangedClassesDescendingRadio.Checked);//descending потому что в UI сортировка по точности, а не по ошибке
            int failsSum = 0;
            for (int i = 0; i < failsClasses.Length; i++)
            {
                failsSum += failsClasses[i];
            }
            var items = RangedClassesBox.Items;
            items.Clear();
            double[] percents = new double[rangedClasses.Length];
            for (int i = 0; i < rangedClasses.Length; i++)
            {
                percents[i] = failsSum == 0 ? 1 : 1 - (double)failsClasses[i] / (double)failsSum;
                string className = rangedClasses[i];
                items.Add(string.Format(Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_CLASSESTIMATED,
                    i + 1, className, (percents[i] * 100).ToString("#0.00", CultureInfo.CurrentUICulture)));
            }            
            var myPane = RangedClassesGraph.GraphPane;            
            myPane.IsIgnoreMissing = true;
            myPane.Title.Text = RangedClassesGroup.Text;
            myPane.XAxis.Title.Text = Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_CLASSES;
            myPane.YAxis.Title.Text = Resources.BI_PROJECTEXPLORER_CLASSIFICATIONPROBLEM_WITHTRAINING_CLASSIFICATIONMATRIX_CLASSESFAILS;

            // Show the x axis grid
            myPane.XAxis.MajorGrid.IsVisible = true;

            // Make the Y axis scale red
            myPane.YAxis.Scale.FontSpec.FontColor = Color.Red;
            myPane.YAxis.Title.FontSpec.FontColor = Color.Red;
            // Align the Y axis labels so they are flush to the axis
            myPane.YAxis.Scale.Align = AlignP.Inside;
            myPane.XAxis.Type = AxisType.Text;
            myPane.XAxis.Scale.Min = 0;
            myPane.XAxis.Scale.MinorStep = 1;
            myPane.XAxis.Scale.MajorStep = 1;            

            // Fill the axis background with a gradient
            myPane.Chart.Fill = new Fill(Color.White, Color.LightGray, 45.0f);

            // Enable scrollbars if needed
            RangedClassesGraph.IsShowHScrollBar = true;
            RangedClassesGraph.IsShowVScrollBar = true;
            RangedClassesGraph.IsAutoScrollRange = true;

            // OPTIONAL: Show tooltips when the mouse hovers over a point
            RangedClassesGraph.IsShowPointValues = true;

            // Make sure the Graph gets redrawn
            RangedClassesGraph.Invalidate();                        
            //заполняем график                                     
            myPane.XAxis.Scale.TextLabels = rangedClasses;
            BarItem myBar = _bar != null ? _bar : myPane.AddBar(string.Empty, null, GeneralMethods.GetColorByIndex(0));
            for (int i = 0; i < percents.Length; i++)
            {                
                if (_bar == null)
                {
                    myBar.AddPoint(i, percents[i] * 100);                    
                }
                else
                {                    
                    myBar.Points[i].Y = percents[i] * 100;
                }
            }
            _bar = myBar;
            RangedClassesGraph.AxisChange();
            RangedClassesGraph.Invalidate();
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="qualityInfo"></param>
        /// <param name="projectExplorer"></param>
        public ClassificationMatrixDialog(IClassificationProblem problem, ClassificationQualityInfo qualityInfo, ProjectExplorerForm projectExplorer)
        {
            _problem = problem;
            _qualityInfo = qualityInfo;
            _projectExplorer = projectExplorer;
            InitializeComponent();
        }

        private void OKButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void ErrorLevelTipBox_OnRolledDown()
        {            
            _projectExplorer.SimpleMode = true;
            Height = ErrorLevelTipBox.Top + ErrorLevelTipBox.Height + 67;
        }

        private void ErrorLevelTipBox_OnRolledUp()
        {         
            _projectExplorer.SimpleMode = false;
            Height = ErrorLevelTipBox.Top + ErrorLevelTipBox.Height + 67;
        }

        private void ClassificationMatrixDialog_Load(object sender, EventArgs e)
        {
            Initialize();
        }

        private void RangedClassesDescendingRadio_CheckedChanged(object sender, EventArgs e)
        {
            RangeClasses();
        }

        private void RangedClassesAscendingRadio_CheckedChanged(object sender, EventArgs e)
        {
            RangeClasses();
        }

        private void ClassificationMatrixFactVerticalRadio_CheckedChanged(object sender, EventArgs e)
        {
            BuildMatrix();
        }

        private void ClassificationMatrixFactHorizontalRadio_CheckedChanged(object sender, EventArgs e)
        {
            BuildMatrix();
        }
    }
}
